module clk_div #(
    parameter integer DIV_FACTOR = 4
) (
    input  rst_n,
    input  clk_in,
    output clk_out
);

  generate
    if (DIV_FACTOR % 2 == 0) begin : g_even_div
      clk_div_even #(
          .DIV_FACTOR(DIV_FACTOR)
      ) clk_div_inst (
          .clk_in (clk_in),
          .rst_n  (rst_n),
          .clk_out(clk_out)
      );
    end else begin : g_odd_div
      clk_div_odd #(
          .DIV_FACTOR(DIV_FACTOR)
      ) clk_div_inst (
          .clk_in (clk_in),
          .rst_n  (rst_n),
          .clk_out(clk_out)
      );
    end
  endgenerate

endmodule


module clk_div_even #(
    parameter integer DIV_FACTOR = 10
) (
    input  rst_n,
    input  clk_in,
    output clk_out
);

  localparam integer Width = $clog2(DIV_FACTOR);
  localparam integer HalfDiv = DIV_FACTOR / 2;

  reg [Width-1:0] cnt_reg;

  always @(posedge clk_in, negedge rst_n) begin
    if (~rst_n) begin
      cnt_reg <= 0;
    end else if (cnt_reg == DIV_FACTOR - 1) begin
      cnt_reg <= 0;
    end else begin
      cnt_reg <= cnt_reg + 1'b1;
    end
  end

  reg clk_div;
  always @(posedge clk_in, negedge rst_n) begin
    if (~rst_n) begin
      clk_div <= 1'b0;
    end else if (cnt_reg == HalfDiv - 1) begin
      clk_div <= 1'b0;
    end else if (cnt_reg == DIV_FACTOR - 1) begin
      clk_div <= 1'b1;
    end
  end
  assign clk_out = clk_div;

endmodule

module clk_div_odd #(
    parameter integer DIV_FACTOR = 10
) (
    input  rst_n,
    input  clk_in,
    output clk_out
);

  localparam integer Width = $clog2(DIV_FACTOR);
  localparam integer HalfDiv = DIV_FACTOR / 2;

  reg [Width-1:0] cnt_reg;
  reg clk_div_pos;
  reg clk_div_neg;

  always @(posedge clk_in, negedge rst_n) begin
    if (~rst_n) begin
      cnt_reg <= 0;
    end else if (cnt_reg == DIV_FACTOR - 1) begin
      cnt_reg <= 0;
    end else begin
      cnt_reg <= cnt_reg + 1'b1;
    end
  end

  // posedge div
  always @(posedge clk_in, negedge rst_n) begin
    if (~rst_n) begin
      clk_div_pos <= 1'b0;
    end else if (cnt_reg == HalfDiv) begin
      clk_div_pos <= 1'b0;
    end else if (cnt_reg == DIV_FACTOR - 1) begin
      clk_div_pos <= 1'b1;
    end
  end

  // negedge div
  always @(negedge clk_in, negedge rst_n) begin
    if (~rst_n) begin
      clk_div_neg <= 1'b0;
    end else if (cnt_reg == HalfDiv) begin
      clk_div_neg <= 1'b0;
    end else if (cnt_reg == DIV_FACTOR - 1) begin
      clk_div_neg <= 1'b1;
    end
  end
  assign clk_out = clk_div_neg & clk_div_pos;

endmodule
